package com.shao.intelligentsnake;

/**
 * @author shaohuailin
 * @date 2024/4/20
 */
public class Automatic implements Runnable {

    private GameScene scene;
    private GameParams sceneParams;

    public Automatic(GameScene scene) {
        this.scene = scene;
        sceneParams = scene.getParams();
    }

    /**
     * 开启
     */
    public void open() {
        Thread thread = new Thread(this);
        thread.setDaemon(true);
        thread.start();
    }

    @Override
    public void run() {
        int sleep = 50;

        try {

            while (true) {
                boolean gameOver = sceneParams.isGameOver();
                boolean openAutomatic = sceneParams.isOpenAutomatic();
                int[] snakePosition = sceneParams.getSnakePosition();
                int foodPosition = sceneParams.getFoodPosition();
                int[] stateTable = sceneParams.getStateTable();
                int size = sceneParams.getSize();
                // 若未开启自动模式或者游戏结束，退出循环
                if (!openAutomatic || gameOver) {
                    break;
                }
                // 创建探测器(先测试无向的)(现在我们试试有向的)
                // Probe probe = new UndirectedProbe(stateTable, size);
                Probe probe = new DirectedProbe(stateTable, size);
                // 找可以行动路径
                int[] positions = doStrategy(snakePosition, foodPosition, probe);
                // 策略分析完，还是没有可达到路径
                if (positions.length == 0) {
                    System.out.println("我找不到路可走了");
                    break;
                }
                // 由于每移动一次都有可能游戏结束，所以移动次数不一定是positions的长度。
                doAction(positions, sleep);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Automatic:自动模式结束");
    }

    /**
     * 去根据策略找可以行动的路径
     *
     * @param snakePosition 蛇位置数组
     * @param foodPosition 食物位置
     * @param probe 探测器
     * @return 返回路径位置数组
     */
    private int[] doStrategy(int[] snakePosition, int foodPosition, Probe probe) {
        // 按最简单的策略
        System.out.println("尝试简单策略");
        ActionStrategy strategy = new SimpleActionStrategy(snakePosition[0], foodPosition, probe);
        int[] positions = strategy.apply();
        // 简单策略不可达，采用最短路策略
        if (positions.length == 0) {
            System.out.println("最短路策略不可达，尝试最短路策略");
            strategy = new ShortActionStrategy(snakePosition[0], foodPosition, probe);
            positions = strategy.apply();
            // 最短路策略不可达，采用走尾巴最短路策略
            if (positions.length == 0) {
                System.out.println("最短路策略不可达，尝试走尾巴");
                int tailPosition = snakePosition[snakePosition.length - 1];
                strategy = new TailActionStrategy(snakePosition[0], tailPosition, probe);
                // ===========================================
                // 这块后期可以优化掉，TailActionStrategy要优化
                // TailActionStrategy的tailProbe采用无向探测
                UndirectedProbe selfProbe = new UndirectedProbe(sceneParams.getStateTable(), sceneParams.getSize());
                ((TailActionStrategy) strategy).setTailProbe(selfProbe);
                positions = strategy.apply();
                if (positions.length > 0) {
                    System.out.println("向尾巴走一步，缓解局势");
                    positions = new int[] {positions[0]};
                }
                // ===========================================

                if (positions.length == 0) {
                    System.out.println("尾巴走不通");
                }
            }
        }
        return positions;
    }

    /**
     * 去移动位置，如果过程中遇到失败就会退出移动。
     *
     * @param positions 位置数组
     * @param sleep 间隔时间
     * @return true移动成功 false移动失败
     * @throws InterruptedException
     */
    private boolean doAction(int[] positions, int sleep) throws InterruptedException {
        for (int position : positions) {
            boolean action = doAction(position, sleep);
            if (!action) {
                return false;
            }
        }
        return true;
    }
    private boolean doAction(int position, int sleep) throws InterruptedException {
        Thread.sleep(sleep);
        scene.doMovePosition(position);
        return !sceneParams.isGameOver();
    }
}
